package com.ebupt.migu.music.popup.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ebupt.migu.globalpopup.entity.*;
import com.ebupt.migu.globalpopup.enums.ConditionEnum;
import com.ebupt.migu.music.commons.constants.ResultMsg;
import com.ebupt.migu.music.commons.constants.SysConstant;
import com.ebupt.migu.music.commons.utils.ConditionUtil;
import com.ebupt.migu.music.commons.utils.DateUtil;
import com.ebupt.migu.music.popup.dto.ActionListDTO;
import com.ebupt.migu.music.popup.service.ActionListService;
import com.ebupt.migu.music.popup.vo.ActionListVO;
import com.ebupt.migu.music.popup.vo.ActionSortVO;
import com.ebupt.migu.music.popup.vo.PageInfoVO;
import com.ebupt.migu.music.redis.service.RedisService;
import com.ebupt.migu.restapi.IopMatchPost;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tz
 */
@Slf4j
@Service
public class ActionListServiceImpl implements ActionListService {

    @Autowired
    private RedisService redisService;

    private static String AID_UID_KEY = "AID_UID_KEY";

    private static String FRE_UID_KEY = "FRE_UID_KEY";

    @Override
    public ResultMsg getActionList(ActionListDTO actionListDTO) {
        log.info("{}开始执行查询逻辑，ActionListDTO：{}",
                DateUtil.parseDateToStr(new Date(), DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS_SSS),
                actionListDTO.toString());
        // long startTime = System.currentTimeMillis();
        // 接口调用起始时间
        Instant beginTime = Instant.now();
        // 从redis获取活动列表信息
        Set<Object> set;
        if ("0".equals(actionListDTO.getType())) {
            set = redisService.getSet(SysConstant.ACTIVITY_LIST_PRIM);
        } else {
            set = redisService.getSet(SysConstant.ACTIVITY_LIST_H5);
        }
        // 遍历set集合取id查具体活动信息
        List<ActionListVO> list = new ArrayList<>();
        if (set.size() > 0) {
            log.info("{}redis中存在活动列表信息，deviceId:{},set.size:{}",
                    DateUtil.parseDateToStr(new Date(), DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS_SSS),
                    actionListDTO.getDeviceId(), set.size());
            for (Object o : set) {
                Object obj = redisService.get(o.toString());
                ActivityRedisBean bean = JSON.parseObject(obj.toString(), ActivityRedisBean.class);
                // 查寻是否已有弹窗
                ActivityInfo activityInfoForPop = bean.getActivityInfo();
                if (activityInfoForPop != null) {
                    if (actionListDTO.getExtra() != null) {
                        Object phone = actionListDTO.getExtra().get(ConditionEnum.MSISDN.getValue());
                        Object uid = actionListDTO.getExtra().get(ConditionEnum.UID.getValue());
                        // 用户人群判断
                        if (StringUtils.isNotEmpty(activityInfoForPop.getUserGroupId())) {
                            if (phone != null) {
                                boolean member = redisService.isMember(activityInfoForPop.getUserGroupId() + "-phone",
                                        phone.toString());
                                if (!member) {
                                    continue;
                                }
                            }
                        }
                        // iop标签验证
                        if (StringUtils.isNotEmpty(activityInfoForPop.getIopTagId())) {
                            IopMatchPost ip = new IopMatchPost();
                            boolean b = false;
                            if (phone != null) {
                                b = ip.iopMatch(activityInfoForPop.getIopTagId(), activityInfoForPop.getActivityId(),
                                        phone.toString());
                            } else {
                                if (uid != null) {
                                    b = ip.iopMatch(activityInfoForPop.getIopTagId(),
                                            activityInfoForPop.getActivityId(), "", uid.toString());
                                }
                            }
                            if (!b) {
                                continue;
                            }
                        }
                    }
                    // 触发频次判断
                    Integer activityTimes = activityInfoForPop.getActivityTimes();
                    if (activityTimes == null) {
                        activityTimes = 1;
                    }
                    if (activityTimes != -1) {
                        boolean hasPop = redisService.exists(AID_UID_KEY + ":" + actionListDTO.getDeviceId() + "-"
                                + bean.getActivityInfo().getActivityId());
                        if (hasPop) {
                            continue;
                        }
                    }
                } else {
                    boolean hasPop = redisService.exists(
                            AID_UID_KEY + ":" + actionListDTO.getDeviceId() + "-" + bean.getActivityInfo().getActivityId());
                    if (hasPop) {
                        continue;
                    }
                }
                // 各种判断处理
                List<ConditionRelation> conditionRelations = bean.getConditionRelations();
                if (conditionRelations.size() > 0) {
                    ConditionUtil conditionTool = ConditionUtil.getConditionUtil();
                    boolean flag = conditionTool.getCondition(actionListDTO.getExtra(), conditionRelations);
                    if (!flag) {
                        continue;
                    }
                }
                // 添加数据
                ActivityInfo activityInfo = bean.getActivityInfo();
                ActionInfo actionInfo = bean.getActionInfo();
                List<PageInfo> pageInfos = bean.getPageInfos();
                List<PageInfoVO> pvo =
                        pageInfos.stream().map(e -> new PageInfoVO(e.getPageKey(), e.getPageName(), e.getContentType(),
                                e.getContentId(), JSONObject.parseObject(e.getFilters()))).collect(Collectors.toList());
                ActionListVO vo = new ActionListVO();
                BeanUtils.copyProperties(activityInfo, vo);
                if (null != actionInfo) {
                    BeanUtils.copyProperties(actionInfo, vo);
                } else {
                    vo.setKeyWord("");
                    vo.setActionResourceId("");
                    vo.setActionResourceType("");
                }
                vo.setPageList(pvo);
                list.add(vo);
            }
        }

        // 全局设置次数
        list = popUpTimes(actionListDTO.getDeviceId(), list);
        // 优先级返回
        List<ActionSortVO> sort = list.stream().map(m -> {
            ActionSortVO vo = new ActionSortVO();
            BeanUtils.copyProperties(m, vo);
            vo.setPriority(m.getId());
            return vo;
        }).collect(Collectors.toList());
        ResultMsg res = new ResultMsg();
        res.setMessage("SUCCESS");
        res.setData(sort);
        // long endTime = System.currentTimeMillis();
        Duration duration = Duration.between(beginTime, Instant.now());
        if (duration.toMillis() > 3000) {
            log.info(">>>>>>>>>>>>{}接口用时超过3秒", actionListDTO.getDeviceId());
        }
        log.info("{}接口返回用时：" + duration.toMillis() + "毫秒", actionListDTO.getDeviceId());
        return res;
    }

    /**
     * 全局设置次数过滤
     *
     * @param deviceId
     * @param list
     * @return
     */
    private List<ActionListVO> popUpTimes(String deviceId, List<ActionListVO> list) {
        List<ActionListVO> newlist = new ArrayList<>();
        // 获取用户已弹窗的次数
        Object popUpsSet = redisService.get(FRE_UID_KEY + ":" + deviceId);
        // 获取全局设置的弹窗次数
        Object FrequencySet = redisService.get("activityFrequencySwitch");
        boolean isExceed = true;
        // 得到已经弹窗的次数
        int popUps = popUpsSet != null ? Integer.valueOf(String.valueOf(popUpsSet)).intValue() : 0;
        if (FrequencySet != null) {
            // 得到全局设置的弹窗次数
            int frequency = JSON.parseObject(FrequencySet.toString(), ActivityFrequency.class).getTimes();
            isExceed = popUps >= frequency ? false : true;
            log.info("用户id：{},已弹窗次数：{},全局弹窗规定次数：{}", deviceId, popUps, frequency);
            if (isExceed) {
                list.stream().limit(frequency - popUps).forEach(newlist::add);
            }
            return newlist;
        }
        return list;
    }

    /**
     * 优先级过滤
     *
     * @param list
     * @return
     */
    private List<ActionSortVO> priority(List<ActionListVO> list) {
        // 优先级结果集
        List<ActionSortVO> res = Lists.newArrayList();
        // 按弹窗类型分组
        Map<Integer, List<ActionListVO>> map =
                list.stream().collect(Collectors.groupingBy(ActionListVO::getActivityType));
        // 遍历map，再按照页面分组
        map.forEach((k, v) -> {
            // 需要删除的集合
            Set<ActionListVO> del = new HashSet<>();
            for (int i = 0; i < v.size(); i++) {
                for (int j = i + 1; j < v.size(); j++) {
                    del.add(needDel(v.get(i), v.get(j)));
                }
            }
            // 删除被过滤的集合
            List<ActionListVO> vos = v.stream().filter(e -> !del.contains(e)).collect(Collectors.toList());
            res.addAll(vos.stream().map(m -> {
                ActionSortVO vo = new ActionSortVO();
                BeanUtils.copyProperties(m, vo);
                return vo;
            }).collect(Collectors.toList()));
        });
        return res;
    }

    private ActionListVO needDel(ActionListVO a1, ActionListVO a2) {
        List<PageInfoVO> p1 = a1.getPageList();
        List<PageInfoVO> p2 = a2.getPageList();
        for (PageInfoVO v1 : p1) {
            for (PageInfoVO v2 : p2) {
                // 第一级判断有相同页面
                if (v1.getPageKey().equals(v2.getPageKey())) {
                    // 第二级判断有相同资源contentId
                    if (StringUtils.isNotEmpty(v1.getPageContentId())
                            && StringUtils.isNotEmpty(v2.getPageContentId())) {
                        if (v1.getPageContentId().equals(v2.getPageContentId())) {
                            return a1.getId() < a2.getId() ? a1 : a2;
                        }
                    } else {
                        return a1.getId() < a2.getId() ? a1 : a2;
                    }
                }
            }
        }
        return null;
    }

}
